// (C) 2021 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1 ns / 1 ps
  
module channel_ctrl_top
    #(
        parameter MASTER = 1
     )
(
input                 clk, //only used at master side, inout to pll inside tx_soft_lvds
input                 rst_n,
input                 mcsi_system_rstn,
output                tx_coreclock,
output                tx_pll_locked,

input                 lvds_clk_in,
output                lvds_clk_out,                      
input                 lvds_rx_in,
output                lvds_tx_out,      

input    [11:0][3:0]  i2c_event_i, //i2c relay translates i2c signal into encoded events.
output   [11:0][3:0]  i2c_event_o, //send encoded events to relay then recover i2c signals onto bus.

input    [ 1:0][3:0]  uart_i,
output   [ 1:0][3:0]  uart_o,

input    [7:0]        GPIO_i,
output   [7:0]        GPIO_o,

input    [7:0]        lvds_mm_i,
output   [7:0]        lvds_mm_o,
                      
output   [7:0]        frame_count,
output   [3:0]        tx_frm_offset,
output   [3:0]        rx_frm_offset,
output   [7:0]        frame_count_check,
output                gpio_i_sample_en,
output                gpio_o_sample_en,
                      
input                 bist_mode_enable,
input    [1:0]        inject_frame_comma_err,
input    [1:0]        inject_frame_crc_err,
output                frame_crc_err,
output                bist_err,
output                frame_comma_err,
output                frame_loss_crc_H2A,        //Indicates H2A direction has frame error
output                frame_aligned_tx,          //indicates H2A aligned at host side or A2H aligned at agent side
output                frame_loss_crc_A2H,        //Indicates A2H direction has frame error
output                aligned
);

wire [9:0] lvds_rx_data;
wire [9:0] lvds_tx_data;  
wire       bit_slip;                                       
wire       rx_inclock;
wire       rx_outclock;
wire       tx_outclock;
wire [9:0] lvds_rx_data_synced;
wire       fifo_rdempty;
wire       rx_pll_locked;
wire       link_training_err;

reg        bit_slip_sync1;
reg        bit_slip_sync2;

assign lvds_clk_out   = tx_outclock;
assign rx_inclock     = lvds_clk_in;

//========================================= Sync Tx and Rx Fifo ==============================

dualpFifo wr_dcfifo(
    .aclr    ( ~tx_pll_locked || ~rx_pll_locked || ~mcsi_system_rstn ), //release after tx_pll locked and rx_pll_locked
    .data    ( lvds_rx_data                        ),
    .rdclk   ( tx_coreclock                        ),
    .rdreq   ( 1'b1                                ),
    .wrclk   ( rx_outclock                         ),
    .wrreq   ( 1'b1                                ),
    .q       ( lvds_rx_data_synced                 ),
    .rdempty ( fifo_rdempty                        ),
    .rdfull  (                                     ),
    .rdusedw (                                     ),
    .wrempty (                                     ),
    .wrfull  (                                     ),
    .wrusedw (                                     )
);

//syncronizer

always@(posedge rx_outclock) begin: bit_slip_syncronizer
    bit_slip_sync1 <= bit_slip;
    bit_slip_sync2 <= bit_slip_sync1;
end
    
    
lvds_rx lvds_rx_inst (
    .rx_inclock            ( rx_inclock     ),  
    .rx_in                 ( lvds_rx_in     ),  
    .rx_out                ( lvds_rx_data   ),  
    .rx_data_align         ( bit_slip_sync2 ),  
    .rx_outclock           ( rx_outclock    ),  
    .pll_areset            ( !rst_n         ),  
    .rx_locked             ( rx_pll_locked  )   
);

generate 
    if (MASTER) begin //Master side channel_ctrl module uses tx_inclock as source clk
        lvds_tx lvds_tx_inst (
         .tx_in                 ( lvds_tx_data   ), 
         .tx_out                ( lvds_tx_out    ), 
         .tx_outclock           ( tx_outclock    ), //LVDS source synchronize clock
         .tx_coreclock          ( tx_coreclock   ), //Used to drive logic inside channel_ctrl
         .tx_inclock            ( clk            ), 
         .pll_areset            ( !rst_n         ), 
         .tx_locked             ( tx_pll_locked  ) 
        );
    end else begin    //Slave side channel_ctrl module uses lvds_clk_in as source clk
        lvds_tx lvds_tx_inst (
         .tx_in                 ( lvds_tx_data  ), 
         .tx_out                ( lvds_tx_out   ), 
         .tx_outclock           ( tx_outclock   ), 
         .tx_coreclock          ( tx_coreclock  ), 
         .tx_inclock            ( rx_inclock    ), 
         .pll_areset            ( !rst_n        ), 
         .tx_locked             ( tx_pll_locked ) 
        );
    end
endgenerate


generate begin: channel_ctrl
   if(MASTER) begin: u1
	   lvds_channel_ctrl_host
      #(
          .CONSECUTIVE_K28_5_LOCK(5),               //Define how many K28.5 comma should be consecutive detected
          .CONSECUTIVE_K28_1_LOCK(5),               //Define how many K28.1 comma should be consecutive detected
          .CONSECUTIVE_K28_1_Loss(3),               //Define how many K28.1 comma are consecutive detected loss
          .CONSECUTIVE_CRC_Loss(10)                 //Define how many CRC check are consecutive detected wrong
      )
      lvds_channel_ctrl_host_inst
      (
          .reset_n            ( tx_pll_locked                      ),
          .clock              ( tx_coreclock                       ),
                                                             
          .bist_mode_enable   ( bist_mode_enable                   ),
			 .inject_frame_comma_err (inject_frame_comma_err          ),
			 .inject_frame_crc_err   (inject_frame_crc_err            ),
          .lvds_rx_data       ( lvds_rx_data_synced                ), //data from lvds_rx need go through CDC, foe example dpFIFO
          .lvds_tx_data       ( lvds_tx_data                       ),
          .frame_length       ( 4'd11                              ),
          .fifo_rdempty       ( fifo_rdempty                       ),
          .data_tx0           ( {i2c_event_i[1] , i2c_event_i[0] } ),
          .data_tx1           ( {i2c_event_i[3] , i2c_event_i[2] } ),
          .data_tx2           ( {i2c_event_i[5] , i2c_event_i[4] } ),
          .data_tx3           ( {i2c_event_i[7] , i2c_event_i[6] } ),
          .data_tx4           ( {i2c_event_i[9] , i2c_event_i[8] } ),
          .data_tx5           ( {i2c_event_i[11], i2c_event_i[10]} ),
          .data_tx6           ( lvds_mm_i                          ), //reserved for LVDS_MM
          .data_tx7           ( {uart_i[1]      , uart_i[0]      } ), //reserved for uart
          .data_tx8           ( GPIO_i                             ),
                                                               
          .data_rx0           ( {i2c_event_o[1] , i2c_event_o[0] } ),
          .data_rx1           ( {i2c_event_o[3] , i2c_event_o[2] } ),
          .data_rx2           ( {i2c_event_o[5] , i2c_event_o[4] } ),
          .data_rx3           ( {i2c_event_o[7] , i2c_event_o[6] } ),
          .data_rx4           ( {i2c_event_o[9] , i2c_event_o[8] } ),
          .data_rx5           ( {i2c_event_o[11], i2c_event_o[10]} ),
          .data_rx6           ( lvds_mm_o                          ), //reserved for LVDS_MM
          .data_rx7           ( {uart_o[1]      , uart_o[0]      } ), //reserved for uart
          .data_rx8           ( GPIO_o                             ),
          .frame_count        ( frame_count                        ),
          .tx_frm_offset      ( tx_frm_offset                      ),
          .rx_frm_offset      ( rx_frm_offset                      ),
          .frame_count_check  ( frame_count_check                  ),
          .gpio_i_sample_en   ( gpio_i_sample_en                   ),
          .gpio_o_sample_en   ( gpio_o_sample_en                   ),    
          .bit_slip           ( bit_slip                           ),
          .aligned            ( aligned                            ),
          .frame_crc_err      ( frame_crc_err                      ),
	  .link_training_err  ( link_training_err                  ),
	  .frame_comma_err    ( frame_comma_err                    ),
	  .frame_loss_crc_A2H ( frame_loss_crc_A2H                 ),
	  .frame_aligned_tx   ( frame_aligned_tx                   ),
	  .frame_loss_crc_H2A ( frame_loss_crc_H2A                 ),
          .bist_err           ( bist_err                           )
      );
	end
	else begin: u2
	   lvds_channel_ctrl_agent
      #(
          .CONSECUTIVE_K28_5_LOCK(5),               //Define how many K28.5 comma should be consecutive detected
          .CONSECUTIVE_K28_1_LOCK(5),               //Define how many K28.1 comma should be consecutive detected
          .CONSECUTIVE_K28_1_Loss(3),               //Define how many K28.1 comma are consecutive detected loss
          .CONSECUTIVE_CRC_Loss(10)                 //Define how many CRC check are consecutive detected wrong
      )
      lvds_channel_ctrl_agent_inst
      (
          .reset_n            ( tx_pll_locked                      ),
          .clock              ( tx_coreclock                       ),
                                                             
          .bist_mode_enable   (                                    ),
			 .inject_frame_comma_err (inject_frame_comma_err          ),
			 .inject_frame_crc_err   (inject_frame_crc_err            ),
          .lvds_rx_data       ( lvds_rx_data_synced                ), //data from lvds_rx need go through CDC, foe example dpFIFO
          .lvds_tx_data       ( lvds_tx_data                       ),
          .frame_length       ( 4'd11                              ),
          .fifo_rdempty       ( fifo_rdempty                       ),
          .data_tx0           ( {i2c_event_i[1] , i2c_event_i[0] } ),
          .data_tx1           ( {i2c_event_i[3] , i2c_event_i[2] } ),
          .data_tx2           ( {i2c_event_i[5] , i2c_event_i[4] } ),
          .data_tx3           ( {i2c_event_i[7] , i2c_event_i[6] } ),
          .data_tx4           ( {i2c_event_i[9] , i2c_event_i[8] } ),
          .data_tx5           ( {i2c_event_i[11], i2c_event_i[10]} ),
          .data_tx6           ( lvds_mm_i                          ), //reserved for LVDS_MM
          .data_tx7           ( {uart_i[1]      , uart_i[0]      } ), //reserved for uart
          .data_tx8           ( GPIO_i                             ),
                                                               
          .data_rx0           ( {i2c_event_o[1] , i2c_event_o[0] } ),
          .data_rx1           ( {i2c_event_o[3] , i2c_event_o[2] } ),
          .data_rx2           ( {i2c_event_o[5] , i2c_event_o[4] } ),
          .data_rx3           ( {i2c_event_o[7] , i2c_event_o[6] } ),
          .data_rx4           ( {i2c_event_o[9] , i2c_event_o[8] } ),
          .data_rx5           ( {i2c_event_o[11], i2c_event_o[10]} ),
          .data_rx6           ( lvds_mm_o                          ), //reserved for LVDS_MM
          .data_rx7           ( {uart_o[1]      , uart_o[0]      } ), //reserved for uart
          .data_rx8           ( GPIO_o                             ),
          .frame_count        ( frame_count                        ),
          .tx_frm_offset      ( tx_frm_offset                      ),
          .rx_frm_offset      ( rx_frm_offset                      ),
          .frame_count_check  ( frame_count_check                  ),
          .gpio_i_sample_en   ( gpio_i_sample_en                   ),
          .gpio_o_sample_en   ( gpio_o_sample_en                   ),    
          .bit_slip           ( bit_slip                           ),
          .aligned            ( aligned                            ),
          .frame_crc_err      ( frame_crc_err                      ),
	       .link_training_err  ( link_training_err                  ),
			 .frame_comma_err    ( frame_comma_err                    ),
			 .frame_loss_crc_A2H ( frame_loss_crc_A2H                 ),
			 .frame_aligned_tx   ( frame_aligned_tx                   ),
			 .frame_loss_crc_H2A ( frame_loss_crc_H2A                 ),
          .bist_err           ( bist_err                           )
      );   
	end
end
endgenerate

endmodule
